package v1

import (
	"encoding/hex"
	"fmt"
	"runtime"
	"runtime/debug"
	"strconv"
	"strings"
	"time"

	"github.com/gogf/gf/v2/container/garray"
	"github.com/gogf/gf/v2/container/gqueue"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/gtcp"
	"github.com/gogf/gf/v2/os/gcache"
	"github.com/gogf/gf/v2/os/gcron"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gutil"
	"golang.org/x/net/context"
)

type Jt809Login struct {
	UserID           uint32
	Password         string
	DownLinkIP       string
	DownLinkPort     uint16
	MSG_GNSSCENTERID uint32
}

type LoginSend struct {
	MSG_LENGTH       string
	MSG_SN           string
	MSG_ID           string
	MSG_GNSSCENTERID string
	VERSION_FLAG     string
	ENCRYPT_FLAG     string
	ENCRYPT_KEY      string
	UserID           string
	Password         string
	DownLinkIP       string
	DownLinkPort     string
	CRC_CODE         string
}

var ctx = gctx.New()
var (
	//ctx   = gctx.New()
	cache = gcache.New()
)

// res, _ := g.DB().Model("fa_daoru2").All()
var rec []map[string]interface{}

var makeBag = garray.NewStrArray(true)

var q = gqueue.New()

var user *Jt809Login

var SendTcp *LoginSend

var SendMsg *string

const heart = "5B00000018000000001005000C5B510000010000000000F58B5D"

type TcpLogin interface {
	User()
}

type TcpLoginImpotant interface {
	testLogin()
}

func Gfstart() {
	res, _ := g.DB().Model("fa_daoru2").All()
	rec = gvar.New(res).Maps()
}

func (Jt809Login *Jt809Login) User() {
	res, _ := g.DB().Model("fa_jt809Login").Where("id", 1).One()
	Jt809Login.UserID = gvar.New(res["UserID"]).Uint32()
	Jt809Login.Password = gvar.New(res["Password"]).String()
	Jt809Login.DownLinkIP = gvar.New(res["DownLinkIP"]).String()
	Jt809Login.DownLinkPort = gvar.New(res["DownLinkPort"]).Uint16()
	Jt809Login.MSG_GNSSCENTERID = gvar.New(res["MSG_GNSSCENTERID"]).Uint32()
	user = Jt809Login
}

func (LoginSend *LoginSend) testLogin() {
	LoginSend.MSG_LENGTH = "00000000"
	LoginSend.MSG_SN = strconv.FormatInt(int64(0), 16)                               //uint32
	LoginSend.MSG_ID = "1001"                                                        //uint16
	LoginSend.MSG_GNSSCENTERID = strconv.FormatInt(int64(user.MSG_GNSSCENTERID), 16) //uint32
	LoginSend.VERSION_FLAG = "01020F"                                                //[]byte
	LoginSend.ENCRYPT_FLAG = "00"                                                    //byte
	LoginSend.ENCRYPT_KEY = strconv.FormatInt(int64(0), 16)                          //uint32
	LoginSend.UserID = strconv.FormatInt(int64(user.UserID), 16)
	LoginSend.Password = hex.EncodeToString([]byte(user.Password))
	LoginSend.DownLinkIP = hex.EncodeToString([]byte(user.DownLinkIP))
	LoginSend.DownLinkPort = strconv.FormatInt(int64(user.DownLinkPort), 16)
	LoginSend.CRC_CODE = strconv.FormatInt(int64(9578), 16)
	SendTcp = LoginSend
}

type checkLength interface {
	MSG_SNCheck()
	MSG_IDCheck()
	MSG_GNSSCENTERIDCheck()
	ENCRYPT_KEYCheck()
	UserIDCheck()
	PasswordCheck()
	DownLinkIPCheck()
	DownLinkPortCheck()
}

type SendFormat interface {
	SendMsg()
}

func (t *LoginSend) MSG_SNCheck() {
	t.MSG_SN = strconv.FormatInt(int64(0), 16)
	if gvar.New(t.MSG_SN).Int() < 8 {
		supple := 8 - len(t.MSG_SN)
		SendTcp.MSG_SN = supplement(supple) + t.MSG_SN
	}
}

func (t *LoginSend) MSG_IDCheck() {
	t.MSG_ID = SendTcp.MSG_ID
	if gvar.New(t.MSG_SN).Int() < 4 {
		supple := 4 - len(t.MSG_ID)
		SendTcp.MSG_ID = supplement(supple) + t.MSG_ID
	}
}

func (t *LoginSend) MSG_GNSSCENTERIDCheck() {
	t.MSG_GNSSCENTERID = SendTcp.MSG_GNSSCENTERID
	if gvar.New(t.MSG_GNSSCENTERID).Int() < 8 {
		supple := 8 - len(t.MSG_GNSSCENTERID)
		SendTcp.MSG_GNSSCENTERID = supplement(supple) + t.MSG_GNSSCENTERID
	}
}

func (t *LoginSend) ENCRYPT_KEYCheck() {
	t.ENCRYPT_KEY = SendTcp.ENCRYPT_KEY
	if gvar.New(t.ENCRYPT_KEY).Int() < 8 {
		supple := 8 - len(t.ENCRYPT_KEY)
		SendTcp.ENCRYPT_KEY = supplement(supple) + t.ENCRYPT_KEY
	}
}

func (t *LoginSend) UserIDCheck() {
	t.UserID = SendTcp.UserID
	if gvar.New(t.UserID).Int() < 8 {
		supple := 8 - len(t.UserID)
		SendTcp.UserID = supplement(supple) + t.UserID
	}
}

func (t *LoginSend) PasswordCheck() {
	t.Password = SendTcp.Password
	if gvar.New(t.Password).Int() < 16 {
		supple := 16 - len(t.Password)
		SendTcp.Password = supplement(supple) + t.Password
	}
}

func (t *LoginSend) DownLinkIPCheck() {
	t.DownLinkIP = SendTcp.DownLinkIP
	if gvar.New(t.DownLinkIP).Int() < 64 {
		supple := 64 - len(t.DownLinkIP)
		SendTcp.DownLinkIP = t.DownLinkIP + supplement(supple)
	}
}

func (t *LoginSend) DownLinkPortCheck() {
	t.DownLinkPort = SendTcp.DownLinkPort
	if gvar.New(t.DownLinkPort).Int() < 4 {
		supple := 4 - len(t.DownLinkPort)
		SendTcp.DownLinkPort = supplement(supple) + t.DownLinkPort
	}
}

func supplement(num int) string {
	var count string
	for i := 0; i < num; i++ {
		count = count + "0"
	}
	return count
}

func (LoginSend *LoginSend) SendMsg() {
	str := LoginSend.MSG_LENGTH + LoginSend.MSG_SN + LoginSend.MSG_ID + LoginSend.MSG_GNSSCENTERID + LoginSend.VERSION_FLAG + LoginSend.ENCRYPT_FLAG + LoginSend.ENCRYPT_KEY + LoginSend.UserID + LoginSend.Password + LoginSend.DownLinkIP + LoginSend.DownLinkPort + LoginSend.CRC_CODE
	lenth := gvar.New(strconv.FormatInt(int64(len(str)/2), 16)).String()
	if len(lenth) < 8 {
		supple := 8 - len(lenth)
		SendTcp.MSG_LENGTH = supplement(supple) + lenth
	}
	str = LoginSend.MSG_LENGTH + LoginSend.MSG_SN + LoginSend.MSG_ID + LoginSend.MSG_GNSSCENTERID + LoginSend.VERSION_FLAG + LoginSend.ENCRYPT_FLAG + LoginSend.ENCRYPT_KEY + LoginSend.UserID + LoginSend.Password + LoginSend.DownLinkIP + LoginSend.DownLinkPort + LoginSend.CRC_CODE
	str = "5b" + Make(str) + "5d"
	SendMsg = &str
}

func Make(str string) string {
	save := []string{}
	//check := 0
	//save := make([]map[string]string, 0)
	for i, v := range str {
		if i%2 != 0 {
			save = append(save, string(str[i-1])+string(v))
		}
	}
	strArrayNew := ortherStartZhuanyi(save)
	return strArrayNew
}

func ortherStartZhuanyi(arr []string) string {
	for k, v := range arr {
		check := containsString(v, "5b")
		if check {
			arr[k] = strings.Replace(v, "5b", "5a01", 1)
		}
		check = containsString(v, "5a")
		if check {
			arr[k] = strings.Replace(v, "5a", "5a02", 1)
		}
		check = containsString(v, "5d")
		if check {
			arr[k] = strings.Replace(v, "5d", "5e01", 1)
		}
		check = containsString(v, "5e")
		if check {
			arr[k] = strings.Replace(v, "5e", "5e02", 1)
		}
	}
	strArrayNew := strings.Join(arr, ",")
	str := strings.Replace(strArrayNew, ",", "", -1)
	return str
}

func Jt809() {
	TcpLogin.User(&Jt809Login{})
	TcpLoginImpotant.testLogin(&LoginSend{})
	checkLength.MSG_SNCheck(&LoginSend{MSG_SN: SendTcp.MSG_SN})
	checkLength.MSG_IDCheck(&LoginSend{MSG_ID: SendTcp.MSG_ID})
	checkLength.MSG_GNSSCENTERIDCheck(&LoginSend{MSG_GNSSCENTERID: SendTcp.MSG_GNSSCENTERID})
	checkLength.ENCRYPT_KEYCheck(&LoginSend{ENCRYPT_KEY: SendTcp.ENCRYPT_KEY})
	checkLength.UserIDCheck(&LoginSend{UserID: SendTcp.UserID})
	checkLength.PasswordCheck(&LoginSend{Password: SendTcp.Password})
	checkLength.DownLinkIPCheck(&LoginSend{DownLinkIP: SendTcp.DownLinkIP})
	checkLength.DownLinkPortCheck(&LoginSend{DownLinkPort: SendTcp.DownLinkPort})
	SendFormat.SendMsg(SendTcp)
	//var (
	//	err2 error
	//	//ctx = gctx.New()
	//)
	src2, _ := hex.DecodeString(heart)
	src, _ := hex.DecodeString(gvar.New(SendMsg).String())

	for {
		if conn, err := gtcp.NewConn("47.111.114.204:39698"); err == nil {
			//这行后期要删掉
			if err := conn.Send(src); err != nil {
				glog.Error(ctx, err)
			}
			_, err2 := gcron.Add(ctx, "*/60 * * * * *", func(ctx context.Context) {
				if err := conn.Send(src2); err != nil {
					glog.Error(ctx, err)
				} else {
					//gutil.Dump("心跳发送成功 发送时间：" + gtime.Now().Format("Y-m-d H:i:s"))
				}
			}, "heartbeat")
			if err2 != nil {
				panic(err2)
			}
			for {
				if b, err := conn.Recv(-1); err == nil {
					str := hex.EncodeToString(b)
					// gutil.Dump("接收到的消息：" + str)
					q.Push(str)
				} else {
					fmt.Println(err)
					break
				}
			}
			gcron.Remove("heartbeat")
			connErr := conn.Close()
			if connErr != nil {
				glog.Error(ctx, err)
				return
			}
		} else {
			glog.Error(ctx, err)
		}
		gutil.Dump("当前时间" + gtime.Datetime())
		printMemStats("After GC")
		time.Sleep(10 * time.Second)
		gutil.Dump("正在回收GC")
		runtime.GC()
		time.Sleep(5 * time.Second)
		// 打印最终内存使用情况
		printMemStats("After GC")
		debug.FreeOSMemory()
		makeBag.Clear()
		runtime.GC()
		time.Sleep(20 * time.Second)
		gutil.Dump("正在重新连接上级服务器")
	}
}

func printMemStats(title string) {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	fmt.Printf("%s:\n", title)
	fmt.Println("Alloc: ", m.Alloc/1024, " KB")
	fmt.Println("TotalAlloc: ", m.TotalAlloc/1024, " KB")
	fmt.Println("Sys: ", m.Sys/1024, " KB")
	fmt.Println("NumGC: ", m.NumGC)
	fmt.Println("\n\n")
}

func Repose() {
	for {
		if v := q.Pop(); v != nil {
			//gutil.Dump(v)
			decode(gvar.New(v).String())
		} else {
			break
		}
	}
}
